package game;

import com.jogamp.newt.event.KeyAdapter;
import java.awt.Font;
import com.jogamp.opengl.util.FPSAnimator;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

class GlGraphics extends JFrame
{
    private int width, height;
    private int steps;
    private String title;
    private Field f;
  
    public GlGraphics(int width, int height, String title, final Field f)
    {
        super();
        this.width = width;
        this.height = height;
        this.title = title;
        this.f = f;
        init();
        this.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
        Renderer rend = new Renderer(f.getN(), f.getN());
        GLCanvas canvas = new GLCanvas();
        canvas.setPreferredSize(new Dimension(width, height));
        canvas.setFocusable(true);
        final int w = (width)/f.getN();
        final int h = (height)/f.getN();
        MouseAdapter ma = new MouseAdapter() 
        {

            @Override
            public void mousePressed(MouseEvent e) 
            {
                steps++;
                int x = e.getX() / w;
                int y = e.getY() / h;
                if(e.getButton() == MouseEvent.BUTTON1)
                {                    
                    f.change(x + 1, y + 1);                    
                }
                if(e.getButton() == MouseEvent.BUTTON3)
                {
                    boolean c = false;
                    for(int i = 1; i < f.getN() + 1; i++)
                    {
                        if(f.get(i, y + 1) == 0)
                        {
                            for(int j = i + 1; j < f.getN() + 1; j++)
                            {
                                f.change(j, y + 1);
                            }
                            c = true;
                            break;
                        }                            
                    }
                    if(!c)
                    {
                        for(int i = 1; i < f.getN() + 1; i++)
                        {
                            if(f.get(x + 1, i) == 0)
                            {
                                for(int j = i + 1; j < f.getN() + 1; j++)
                                {
                                    f.change(x + 1, j);
                                }
                                break;
                            }
                        }
                    }
                }
                isFinished();
            }            
        };
        KeyListener ka = new KeyListener()
        {
            @Override
            public void keyPressed(KeyEvent e) 
            {
                switch(e.getKeyCode())
                {
                    case KeyEvent.VK_UP: { f.change(f.xn, f.yn + 1); steps++; break; }
                    case KeyEvent.VK_W: { f.change(f.xn, f.yn + 1); steps++; break; }
                    case KeyEvent.VK_DOWN: { f.change(f.xn, f.yn - 1); steps++; break; }
                    case KeyEvent.VK_S: { f.change(f.xn, f.yn - 1); steps++; break; }
                    case KeyEvent.VK_LEFT: { f.change(f.xn + 1, f.yn); steps++; break; }
                    case KeyEvent.VK_A: { f.change(f.xn + 1, f.yn); steps++; break; }
                    case KeyEvent.VK_RIGHT: { f.change(f.xn - 1, f.yn); steps++;break; }                                            
                    case KeyEvent.VK_D: { f.change(f.xn - 1, f.yn); steps++;break; }
                }
                isFinished();
                if(e.getKeyCode() == KeyEvent.VK_ESCAPE ||
                        e.getKeyCode() == KeyEvent.VK_Q)
                {
                    System.exit(0);
                }
            }

            @Override
            public void keyTyped(KeyEvent e) {                
            }

            @Override
            public void keyReleased(KeyEvent e) {
            }
        };
        canvas.addMouseListener(ma);
        canvas.addKeyListener(ka);
        canvas.addGLEventListener(rend);
        getContentPane().add(canvas);
        
        FPSAnimator animator = new FPSAnimator(canvas, 60);
        animator.start();        
    }
    
    private void init()
    {
        setTitle(title);
        setSize(width, height);
        setLocationRelativeTo(null);
    }
    
    private void isFinished()
    {
        if(f.isSolved())
            showFinalDialog();
    }
    
    private void showFinalDialog()
    {
        final JFrame fa = new JFrame("FINISH!");
        fa.setSize(170, 90);
        fa.setAlwaysOnTop(true);
        
        fa.setUndecorated(true);
        fa.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        fa.setLocationRelativeTo(null);
        fa.setLayout(new FlowLayout());
        fa.setVisible(true);
        JLabel label = new JLabel("Your steps: " + Integer.toString(steps) 
                + ". Try again?");
        
        JButton one = new JButton("Yes!");
        // button yes settings 
        one.setBackground(Color.WHITE);
        one.setFont(new Font("serif", Font.BOLD, 15));
        one.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {
                fa.setVisible(false);     
                setVisible(true);
                steps = 0;
                f.generate();
            }
        });
        
        JButton two = new JButton("No!");
        // button two setting
        two.setBackground(Color.BLACK);
        two.setFont(new Font("sefir", Font.BOLD, 15));
        two.setForeground(Color.WHITE);
        two.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {
                System.exit(0);
            }
        });
        fa.add(label);
        fa.add(one);
        fa.add(two);
        this.setVisible(false);
    }
    
    public class Renderer implements GLEventListener
    {
        private int rows, colums;
        private Pictures pic;
        
        public Renderer(int rows, int colums)
        {
            this.rows = rows;
            this.colums = colums;
        }
        
        @Override
        public void init(GLAutoDrawable drawable) 
        {
            GL2 gl = drawable.getGL().getGL2();
            
            pic = new Pictures(gl, 16);
            gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // set background (clear) color
            gl.glClearDepth(1.0f);
            gl.glEnable(GL2.GL_DEPTH_TEST); // enables depth testing
            gl.glDepthFunc(GL2.GL_LEQUAL);  // the type of depth test to do
            gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST); // best perspective correction
            gl.glShadeModel(GL2.GL_SMOOTH); // blends colors nicely, and smoothes out lighting
            gl.glEnable(GL2.GL_TEXTURE_2D); 
            
            System.out.println("Initialization completed");
        }

        @Override
        public void dispose(GLAutoDrawable glad) 
        {     
            System.out.println("Exit");
            System.exit(0);
        }
        
        @Override
        public void display(GLAutoDrawable glad) 
        {
            GL2 gl = glad.getGL().getGL2();  // get the OpenGL 2 graphics context
            gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); // clear color and depth buffers     
            gl.glClearColor(1, 1, 1, 1);
            gl.glEnable(GL2.GL_BLEND);
            
            gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);             
            
            gl.glMatrixMode(GL2.GL_MODELVIEW);
            gl.glLoadIdentity(); 
            for(int i = 1; i <= f.getN(); i++)
            {
                for(int j = 1; j <= f.getN(); j++)
                {
                    drawRect(gl, i, j);
                }
            }
        }
        
        private void drawRect(GL2 gl, int x, int y)
        {
            x--; y--;
            TextureObject image = null;
            if(f.get(x + 1, y + 1) == 0)
            {
                image = pic.get(0);
            }
            else
            {
                image = pic.get(f.get(x+1, y+1));
            }
            image.bind(gl);
            image.x = x;
            image.y = y;
            image.draw(gl);
            gl.glEnd();
        }

        @Override
        public void reshape(GLAutoDrawable glad, int x, int y, int width, int height) 
        {
            GL2 gl = glad.getGL().getGL2();
            
            gl.glViewport(0, 0, width, height);
            
            gl.glMatrixMode(GL2.GL_PROJECTION);
            gl.glLoadIdentity();
            
            float ratio = (float)width/height;
            gl.glOrtho(0, rows * ratio, colums, 0, -10, 10);
            
            gl.glMatrixMode(GL2.GL_MODELVIEW);
            gl.glLoadIdentity();
        }  
    }       
}